# -*- shell-script -*-

# 00minimal - Minimal, usually empty routines for extra lscfg output.

# This file is part of the Linux lsvpd package.

# (C) Copyright IBM Corp. 2002, 2003, 2004, 2005

# Maintained by Martin Schwenke <martins@au.ibm.com>

# Parts originally derived from work by Todd Inglett.

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
    
# $Id: 00minimal,v 1.1 2006/04/11 18:38:29 emunson Exp $

true || return 0

######################################################################

usage ()
{
    cat <<EOF 1>&2
usage: $0 [options]
options: -h      print this usage message
         -v      Display VPD when available.
         -p      Display system-specific device information.
	 -l name Displays device information for the named device.
	 -d db   Directory db contains database, instead of default.
	 -z tgz  File tgz contains database archive (overrides -d).
EOF
    exit 1
}

process_options ()
{
    # Defaults
    dovpd=false
    systemspecific=false

    options=":hvpl:t:${db_path_option}:z:"
    while getopts ${options} opt "$@" ; do
	case ${opt} in
	    (h) usage                 ;;
	    (v) dovpd=true            ;;
	    (p) systemspecific=true   ;;
	    (l) name="$OPTARG"        ;;
	    (${db_path_option}|z) :   ;; # Done by process_db_path_options().
	    \?)
                echo "unknown option \`${OPTARG}'" 1>&2
		echo 1>&2
		usage
		;;
	esac
    done

    shift $((${OPTIND} - 1))
    [ -n "$1" ] && usage
    return 0
}

######################################################################

print_global_header ()
{
    [ -z "$name" ] || return 0

    echo -n "INSTALLED RESOURCE LIST"
    if $dovpd ; then
	echo " WITH VPD"
    else
	echo
    fi
    echo
    echo "The following resources are installed on the machine."
    if $dovpd ; then
	echo
    else
	echo "+/- = Added or deleted from Resource List."
	echo "*   = Diagnostic support not available."
	echo
    fi
    
    local arch=$(get_architecture)
    echo "  Model Architecture: ${arch}"
    local cpus=$(get_cpus)
    echo "  Model Implementation: ${cpus}, PCI Bus"
    echo
}

######################################################################

render_all ()
{
    do_pre_items </dev/null

    render_all_basic

    do_post_items </dev/null

    if $systemspecific ; then
	do_platform_specific_section
    fi </dev/null
}

render_linux_vpd ()
{
    local x="$1"

    local node="${x%/linux,vpd}"

    local vpd_subdirs
    vpd_subdirs_list_hook "$node"
    local vpd_dir
    for vpd_dir in $vpd_subdirs ; do
	local vpd_value
	vpd_field_get "$vpd_dir" "AX"
	local ax="$vpd_value"
	vpd_field_get "$vpd_dir" "YL"
	local yl="$vpd_value"
	vpd_field_get "$vpd_dir" "DS"
	local ds="$vpd_value"

	if should_render "$node" "$ds" "$ax" "$yl" ; then
	    lscfg_render_header "$ax" "$yl" "$ds"
	    $dovpd && lscfg_render_vpd "$vpd_dir" "$yl"
	fi
    done
}

######################################################################

# A lot of work for a little output.

lscfg_disk_size ()
{
    local disk="$1"

    local blocks

    local f="${db_proc_dir}/partitions"
    [ -r "$f" ] && \
	blocks=$(sed -n -e "s@.* \([0-9][0-9]*\) ${disk}\( .*\)*\$@\1@p" "$f")

    if [ -n "$blocks" ] ; then
	local mb=$((${blocks} * 1024 / 100000000 * 100))
	[ $mb -gt 0 ] && echo "${mb} MB"
    fi
}

# Filling information.
lscfg_wrap_column=78

lscfg_header_fmt="%s %-16s %-21s "
lscfg_header_t=$(printf "$lscfg_header_fmt" "x" "x" "x")
lscfg_ds_column=${#lscfg_header_t}
lscfg_ds_lead_spaces=$(printf "%${lscfg_ds_column}s" "")

lscfg_vpd_leading_spaces=8
lscfg_vpd_label_len=28
lscfg_vpd_leader=$(printf \
    "%$(($lscfg_vpd_label_len + $lscfg_vpd_leading_spaces))s" \
    "")
lscfg_vpd_field_width=$(($lscfg_wrap_column - \
    $lscfg_vpd_label_len - \
    $lscfg_vpd_leading_spaces))

lscfg_fill_field () 
{
    local val="$1"
    local break="$2"
    local width="$3"
    local leader_1="$4"
    local leader_n="$5"

    local p="$leader_1"

    # Trailing spaces in $val threaten to kill us!  Also compact whitespace.
    set -o noglob
    val=$(echo -n $val)
    set +o noglob

    local nl="
" # Not a bug!
    local out=""

    while [ ${#val} -gt $width ] ; do
	# Is there a space at about column $width that we can break at?
        local t="${val:0:$(($width + 2))}"
	local start="${t%[${break}]*}"
	if [ "$start" != "$t" ] ; then
	    local tt="${t//[^${break}]/}"
	    local sep="${tt: -1:1}"
	    [ "$sep" = " " ] && sep=""
	    out="${out}${p}${start}${sep}${nl}"
	    val="${t##*[${break}]}${val:$(($width + 2))}"
	else
	    # Is there a space anywhere?
	    start="${val%%[${break}]*}"
	    if [ "$start" != "$val" ] ; then
		local tt="${val//[^${break}]/}"
		local sep="${tt:0:1}"
		[ "$sep" = " " ] && sep=""
		out="${out}${p}${start}${sep}${nl}"
		val="${val#*[${break}]}"
	    else
		# Can't be broken.
		break
	    fi
	fi
	p="$leader_n"
    done

    echo "${out}${p}${val}"
}

lscfg_render_header ()
{
    local ax="$1"
    local yl="$2"
    local ds="$3"

    local prefix
    if $dovpd || $systemspecific || [ -n "$name" ] ; then
	prefix=" "
    else
	# Hardcode this for now.
	prefix="+"
    fi

    case "$ax" in
	[hs]d[a-z]*)
	    local size=$(lscfg_disk_size "$ax")
	    [ -n "$size" ] && ds="${ds} (${size})"
	    ;;
    esac

    # Filling code.  $lscfg_ds_column is the column where the DS field
    # should start.  If the previous part of the header spills past
    # that column, DS goes on the next line.  Independently of that,
    # DS is split at a space if it goes past $lscfg_wrap_column
    # (although this is done in lscfg_fill_field).
    local header=$(printf "$lscfg_header_fmt" "$prefix" "$ax" "$yl")
    echo -n "$header"

    local p=""
    if [ ${#header} -gt $lscfg_ds_column ] ; then
	echo
	p="$lscfg_ds_lead_spaces"
    fi

    lscfg_fill_field "$ds" " " $(($lscfg_wrap_column - $lscfg_ds_column)) "$p" "$lscfg_ds_lead_spaces" 
}

lscfg_render_vpd ()
{
    local vpd_dir="$1"
    local yl="$2"

    local vpd_fields
    vpd_fields_list_hook "$vpd_dir"

    [ -n "$vpd_fields" ] && echo

    local k vpd_value
    for k in $vpd_fields ; do
	case "$k" in
	    (DS|AX) : ;; # Already done in subdir header.
	    (YL) lscfg_render_vpd_line "$k" "$yl" ;;
	    *)  vpd_field_get "$vpd_dir" "$k"
		lscfg_render_vpd_line "${k%.*}" "$vpd_value"
		;;
	esac
    done
	
    [ -n "$vpd_fields" ] && echo
}

lscfg_render_vpd_line ()
{
    local k="$1"
    local v="$2"

    [ -n "$v" ] || return

    local label=""

    case "$k" in
	DS|AX|FC) 
	    # Special fields, not printed.
	    :
	    ;;
	# Individual fields.
	BR) label="Brand"                      ;;
	CC) label="Customer Card ID Number"    ;;
	CE) label="CCIN Extender"              ;;
	CI) label="CEC ID"                     ;;
	CL) label="Code Level, LID Keyword"    ;;
	DD) label="Device Driver Level"        ;;
	DG) label="Diagnostic Level"           ;;
	EC) label="EC Level"                   ;;
	FG) label="Flag Field"                 ;;
	FN) label="FRU Number"                 ;;
	FU) label="Function Number"            ;;
	LI) label="Load ID"                    ;;
	LL) label="Loadable Microcode Level"   ;;
	MF) label="Manufacturer"               ;;
	MI) label="Product Specific.($k)"      ;;
	MN) label="Manufacture ID"             ;;
	MP) label="Module Plug Count"          ;;
	NA) label="Network Address"            ;;
	NN) label="Node Name"                  ;;
	PA) label="Op Panel Installed"         ;;
	PN) label="Part Number"                ;;
	PR) label="Power"                      ;;
	RD) label="Rack ID"                    ;;
	RL) label="ROS Level and ID"           ;;
	RM) label="Alterable ROM Level"        ;;
	SE) label="Machine/Cabinet Serial No"  ;;
	SI) label="Subsystem Vendor/Device ID" ;;
	SN) label="Serial Number"              ;;
	SZ) label="Size"                       ;;
	TM) label="Machine Type and Model"     ;;
	VI) label="Vendor ID/Device ID"        ;;
	VK) label="Version"                    ;;
	
	# Grouped fields.
	R?) label="Product Specific.($k)"      ;;
	Y?) label="Device Specific.($k)"       ;;
	Z?) label="Device Specific.($k)"       ;;

	VK|CD|MD|DC|PL|U?)
	    # Suppressed fields (CD should already be appended to DS)
	    :
	    ;;

	*) : "$k" ;; #echo "Unknown key ${k}" 1>&2 ;;
    esac

    [ -n "$label" ] && lscfg_render_vpd_value "$k" "$v" "$label"
}

lscfg_render_vpd_value ()
{
    local key="$1"
    local val="$2"
    local lab="$3"

    [ -n "$val" ] || return

    local dots=$(printf "%$(($lscfg_vpd_label_len - ${#lab}))s" "")
    dots="${dots// /.}"

    local break=""
    case "$key" in
	(MF|TM) break=" "  ;;
	(YL)    break="-/" ;;
	(Z?)    break=" ," ;;
    esac
    
    printf "%${lscfg_vpd_leading_spaces}s%s%s" "" "$lab" "$dots"

    if [ -n "$break" ] ; then
	lscfg_fill_field "$val" \
	    "$break" $lscfg_vpd_field_width "" "$lscfg_vpd_leader"
    else
	echo "$val"
    fi
}

######################################################################

do_pre_items ()
{
    :
}

do_post_items ()
{
    :
}

do_platform_specific_section ()
{
    :
}

get_architecture ()
{
    local arch="unknown"

    local f="${db_uname_dir}/machine"
    [ -r "$f" ] && read arch <"$f"

    echo "$arch"
}

get_cpus_basic ()
{
    local count=1

    local f="${db_proc_dir}/cpuinfo"
    [ -f "$f" ] && count=$(grep -c '^processor[^[:alnum:]]*:' "$f")

    if [ $count -lt 2 ] ; then
	echo "Uni-Processor"
    else
	echo "Multiple Processor"
    fi
}

get_cpus ()
{
    get_cpus_basic
}
